import os
import sys
import time
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog, filedialog
from PIL import Image, ImageTk

# 导入自定义模块
from health_check_data import HealthCheckSystem, HealthCheckPackage, HealthCheckItem
from health_check_printer import HealthCheckPrinter
from id_card_integration import IdCardReader

class HealthCheckApp:
    """体检系统GUI界面"""
    
    def __init__(self, root):
        self.root = root
        self.root.title("体检项目打印系统")
        self.root.geometry("1000x650")
        self.root.minsize(800, 600)
        
        # 初始化数据
        self.health_system = HealthCheckSystem()
        self.health_system.create_default_packages()  # 创建默认套餐
        self.printer = HealthCheckPrinter()
        self.id_reader = IdCardReader()
        
        # 自动打印标志
        self.auto_print = tk.BooleanVar(value=False)
        
        # 自动读卡定时器ID
        self.auto_read_timer = None
        
        # 尝试加载身份证读卡器
        self.id_reader.load_dll()
        
        # 当前选中的套餐
        self.selected_package = None
        self.patient_info = {}
        
        # 设置UI
        self.setup_ui()
        
        # 加载现有套餐数据
        self.load_data()
    
    def setup_ui(self):
        """设置用户界面"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding=10)
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 分割面板
        paned = ttk.PanedWindow(main_frame, orient=tk.HORIZONTAL)
        paned.pack(fill=tk.BOTH, expand=True)
        
        # 左侧套餐面板
        left_frame = ttk.LabelFrame(paned, text="体检套餐")
        paned.add(left_frame, weight=1)
        
        # 右侧项目面板
        right_frame = ttk.LabelFrame(paned, text="项目明细")
        paned.add(right_frame, weight=2)
        
        # 套餐列表
        self.setup_package_panel(left_frame)
        
        # 项目明细
        self.setup_items_panel(right_frame)
        
        # 底部操作区域
        bottom_frame = ttk.Frame(main_frame)
        bottom_frame.pack(fill=tk.X, pady=10)
        
        # 患者信息区域
        self.setup_patient_info_panel(bottom_frame)
        
        # 操作按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=10)
        
        # 自动打印复选框
        auto_print_check = ttk.Checkbutton(
            button_frame, 
            text="读卡后自动打印", 
            variable=self.auto_print,
            command=self.toggle_auto_print
        )
        auto_print_check.pack(side=tk.LEFT, padx=5)
        
        # 读卡按钮
        read_card_btn = ttk.Button(button_frame, text="读取身份证", command=self.read_id_card)
        read_card_btn.pack(side=tk.LEFT, padx=5)
        
        # 打印按钮
        print_btn = ttk.Button(button_frame, text="打印体检单", command=self.print_report)
        print_btn.pack(side=tk.LEFT, padx=5)
        
        # 预览按钮
        preview_btn = ttk.Button(button_frame, text="预览体检单", command=self.preview_report)
        preview_btn.pack(side=tk.LEFT, padx=5)
        
        # 保存按钮
        save_btn = ttk.Button(button_frame, text="保存体检单", command=self.save_report)
        save_btn.pack(side=tk.LEFT, padx=5)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
        status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
    def setup_package_panel(self, parent_frame):
        """设置套餐面板"""
        # 套餐列表框架
        list_frame = ttk.Frame(parent_frame)
        list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 滚动条
        scrollbar = ttk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 套餐列表
        self.package_listbox = tk.Listbox(list_frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set)
        self.package_listbox.pack(fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.package_listbox.yview)
        
        # 绑定选择事件
        self.package_listbox.bind('<<ListboxSelect>>', self.on_package_selected)
        
        # 套餐操作按钮
        btn_frame = ttk.Frame(parent_frame)
        btn_frame.pack(fill=tk.X, padx=5, pady=5)
        
        add_btn = ttk.Button(btn_frame, text="添加套餐", command=self.add_package)
        add_btn.pack(side=tk.LEFT, padx=2)
        
        edit_btn = ttk.Button(btn_frame, text="编辑套餐", command=self.edit_package)
        edit_btn.pack(side=tk.LEFT, padx=2)
        
        del_btn = ttk.Button(btn_frame, text="删除套餐", command=self.delete_package)
        del_btn.pack(side=tk.LEFT, padx=2)
    
    def setup_items_panel(self, parent_frame):
        """设置项目明细面板"""
        # 创建Treeview显示项目列表
        columns = ("name", "description", "reference")
        self.items_tree = ttk.Treeview(parent_frame, columns=columns, show="headings")
        
        # 设置列标题
        self.items_tree.heading("name", text="项目名称")
        self.items_tree.heading("description", text="项目描述")
        self.items_tree.heading("reference", text="参考值")
        
        # 设置列宽
        self.items_tree.column("name", width=150)
        self.items_tree.column("description", width=250)
        self.items_tree.column("reference", width=150)
        
        # 添加滚动条
        tree_scroll = ttk.Scrollbar(parent_frame, orient="vertical", command=self.items_tree.yview)
        self.items_tree.configure(yscrollcommand=tree_scroll.set)
        
        # 布局
        tree_scroll.pack(side=tk.RIGHT, fill=tk.Y)
        self.items_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 项目操作按钮
        btn_frame = ttk.Frame(parent_frame)
        btn_frame.pack(fill=tk.X, padx=5, pady=5)
        
        add_btn = ttk.Button(btn_frame, text="添加项目", command=self.add_item)
        add_btn.pack(side=tk.LEFT, padx=2)
        
        edit_btn = ttk.Button(btn_frame, text="编辑项目", command=self.edit_item)
        edit_btn.pack(side=tk.LEFT, padx=2)
        
        del_btn = ttk.Button(btn_frame, text="删除项目", command=self.delete_item)
        del_btn.pack(side=tk.LEFT, padx=2)
    
    def setup_patient_info_panel(self, parent_frame):
        """设置患者信息面板"""
        info_frame = ttk.LabelFrame(parent_frame, text="患者信息")
        info_frame.pack(fill=tk.X, padx=5, pady=5)
        
        # 患者信息标签和输入框
        self.patient_entries = {}
        fields = [
            ("姓名", ""), ("性别", ""), 
            ("年龄", ""), ("身份证号", ""),
            ("单位", "个人体检三项")  # 添加单位字段
        ]
        
        # 创建信息显示和输入区
        for i, (key, value) in enumerate(fields):
            row = i // 2
            col = i % 2
            
            # 标签框架
            frame = ttk.Frame(info_frame)
            frame.grid(row=row, column=col, sticky=tk.W, padx=5, pady=5)
            
            # 字段标签
            label = ttk.Label(frame, text=f"{key}：", width=8)
            label.pack(side=tk.LEFT)
            
            # 输入框
            entry = ttk.Entry(frame, width=20)
            entry.pack(side=tk.LEFT, fill=tk.X, expand=True)
            entry.insert(0, value)
            
            # 特殊处理性别输入框
            if key == "性别":
                entry.destroy()  # 删除之前创建的输入框
                gender_combo = ttk.Combobox(frame, width=17, values=["男", "女"])
                gender_combo.pack(side=tk.LEFT, fill=tk.X, expand=True)
                self.patient_entries[key] = gender_combo
            else:
                self.patient_entries[key] = entry
        
        # 按钮区域
        button_frame = ttk.Frame(info_frame)
        button_frame.grid(row=(len(fields)+1)//2, column=0, columnspan=2, pady=5)
        
        # 保存按钮
        save_btn = ttk.Button(button_frame, text="保存信息", command=self.save_patient_info)
        save_btn.pack(side=tk.LEFT, padx=5)
        
        # 清除按钮
        clear_btn = ttk.Button(button_frame, text="清除信息", command=self.clear_patient_info)
        clear_btn.pack(side=tk.LEFT, padx=5)
    
    def load_data(self):
        """加载现有套餐数据"""
        # 检查是否有保存的数据文件
        data_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "health_packages.json")
        if os.path.exists(data_file):
            if self.health_system.load_from_file(data_file):
                self.status_var.set(f"已加载保存的套餐数据")
        
        # 刷新套餐列表
        self.refresh_package_list()
    
    def save_data(self):
        """保存套餐数据"""
        data_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "health_packages.json")
        if self.health_system.save_to_file(data_file):
            self.status_var.set(f"套餐数据保存成功")
            return True
        else:
            messagebox.showerror("错误", "保存套餐数据失败")
            return False
    
    def refresh_package_list(self):
        """刷新套餐列表"""
        self.package_listbox.delete(0, tk.END)
        for package in self.health_system.packages:
            self.package_listbox.insert(tk.END, str(package))
    
    def refresh_items_list(self):
        """刷新项目列表"""
        # 清空现有项目
        for item in self.items_tree.get_children():
            self.items_tree.delete(item)
        
        # 没有选中套餐则返回
        if not self.selected_package:
            return
        
        # 添加项目到列表
        for item in self.selected_package.items:
            self.items_tree.insert("", tk.END, values=(item.name, item.description, item.reference))
    
    def update_patient_info_display(self):
        """更新患者信息显示"""
        for key, label in self.patient_entries.items():
            if isinstance(label, ttk.Combobox):
                label.set(self.patient_info.get(key, ""))
            else:
                label.delete(0, tk.END)
                label.insert(0, self.patient_info.get(key, ""))
    
    def on_package_selected(self, event):
        """当套餐被选中时"""
        selection = self.package_listbox.curselection()
        if not selection:
            return
        
        index = selection[0]
        if 0 <= index < len(self.health_system.packages):
            self.selected_package = self.health_system.packages[index]
            self.status_var.set(f"已选择套餐: {self.selected_package.name}")
            self.refresh_items_list()
    
    def add_package(self):
        """添加新套餐"""
        name = simpledialog.askstring("新增套餐", "请输入套餐名称:", parent=self.root)
        if not name:
            return
        
        # 检查套餐名称是否已存在
        for package in self.health_system.packages:
            if package.name == name:
                messagebox.showerror("错误", f"套餐 '{name}' 已存在")
                return
        
        # 创建新套餐
        desc = simpledialog.askstring("套餐描述", "请输入套餐描述(可选):", parent=self.root)
        new_package = HealthCheckPackage(name, desc or "")
        
        # 添加到系统
        self.health_system.add_package(new_package)
        
        # 刷新列表并选中新套餐
        self.refresh_package_list()
        self.package_listbox.selection_set(len(self.health_system.packages) - 1)
        self.selected_package = new_package
        
        # 保存数据
        self.save_data()
        
        # 显示新套餐的项目
        self.refresh_items_list()
    
    def edit_package(self):
        """编辑当前套餐"""
        if not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个套餐")
            return
        
        # 编辑套餐名称
        name = simpledialog.askstring("编辑套餐", "请输入新的套餐名称:", 
                                     initialvalue=self.selected_package.name, parent=self.root)
        if not name:
            return
        
        # 检查套餐名称是否与其他套餐重复
        for package in self.health_system.packages:
            if package != self.selected_package and package.name == name:
                messagebox.showerror("错误", f"套餐 '{name}' 已存在")
                return
        
        # 编辑套餐描述
        desc = simpledialog.askstring("套餐描述", "请输入新的套餐描述(可选):", 
                                     initialvalue=self.selected_package.description, parent=self.root)
        
        # 更新套餐
        self.selected_package.name = name
        self.selected_package.description = desc or ""
        
        # 刷新列表
        self.refresh_package_list()
        
        # 保存数据
        self.save_data()
    
    def delete_package(self):
        """删除当前套餐"""
        if not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个套餐")
            return
        
        # 确认删除
        if not messagebox.askyesno("确认", f"确定要删除套餐 '{self.selected_package.name}' 吗?"):
            return
        
        # 删除套餐
        self.health_system.remove_package(self.selected_package.name)
        
        # 清除当前选中
        self.selected_package = None
        
        # 刷新列表
        self.refresh_package_list()
        self.refresh_items_list()
        
        # 保存数据
        self.save_data()
    
    def add_item(self):
        """添加新项目到当前套餐"""
        if not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个套餐")
            return
        
        # 获取项目名称
        name = simpledialog.askstring("新增项目", "请输入项目名称:", parent=self.root)
        if not name:
            return
        
        # 检查项目是否已存在
        for item in self.selected_package.items:
            if item.name == name:
                messagebox.showerror("错误", f"项目 '{name}' 已存在")
                return
        
        # 获取项目描述
        desc = simpledialog.askstring("项目描述", "请输入项目描述(可选):", parent=self.root)
        
        # 获取参考值
        reference = simpledialog.askstring("参考值", "请输入参考值(可选):", parent=self.root)
        
        # 创建新项目
        new_item = HealthCheckItem(name, desc or "")
        new_item.reference = reference or ""
        
        # 添加到套餐
        self.selected_package.add_item(new_item)
        
        # 刷新项目列表
        self.refresh_items_list()
        
        # 保存数据
        self.save_data()
    
    def edit_item(self):
        """编辑选中的项目"""
        selection = self.items_tree.selection()
        if not selection or not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个项目")
            return
        
        # 获取当前选中项目
        item_id = selection[0]
        item_values = self.items_tree.item(item_id)['values']
        if not item_values or len(item_values) < 1:
            return
        
        current_name = item_values[0]
        current_item = None
        
        # 查找对应项目
        for item in self.selected_package.items:
            if item.name == current_name:
                current_item = item
                break
        
        if not current_item:
            messagebox.showerror("错误", "找不到所选项目")
            return
        
        # 编辑项目名称
        name = simpledialog.askstring("编辑项目", "请输入新的项目名称:", 
                                     initialvalue=current_item.name, parent=self.root)
        if not name:
            return
        
        # 检查项目名称是否与其他项目重复
        for item in self.selected_package.items:
            if item != current_item and item.name == name:
                messagebox.showerror("错误", f"项目 '{name}' 已存在")
                return
        
        # 编辑项目描述
        desc = simpledialog.askstring("项目描述", "请输入新的项目描述(可选):", 
                                     initialvalue=current_item.description, parent=self.root)
        
        # 编辑参考值
        reference = simpledialog.askstring("参考值", "请输入新的参考值(可选):", 
                                          initialvalue=current_item.reference, parent=self.root)
        
        # 更新项目
        current_item.name = name
        current_item.description = desc or ""
        current_item.reference = reference or ""
        
        # 刷新项目列表
        self.refresh_items_list()
        
        # 保存数据
        self.save_data()
    
    def delete_item(self):
        """删除选中的项目"""
        selection = self.items_tree.selection()
        if not selection or not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个项目")
            return
        
        # 获取当前选中项目
        item_id = selection[0]
        item_values = self.items_tree.item(item_id)['values']
        if not item_values or len(item_values) < 1:
            return
        
        current_name = item_values[0]
        
        # 确认删除
        if not messagebox.askyesno("确认", f"确定要删除项目 '{current_name}' 吗?"):
            return
        
        # 删除项目
        if self.selected_package.remove_item(current_name):
            # 刷新项目列表
            self.refresh_items_list()
            
            # 保存数据
            self.save_data()
        else:
            messagebox.showerror("错误", f"删除项目 '{current_name}' 失败")
    
    def toggle_auto_print(self):
        """切换自动打印状态"""
        if self.auto_print.get():
            self.status_var.set("已开启自动模式")
            # 开启自动读卡
            self.start_auto_read()
        else:
            self.status_var.set("已关闭自动模式")
            # 停止自动读卡
            self.stop_auto_read()

    def start_auto_read(self):
        """开始自动读卡"""
        if not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个体检套餐")
            self.auto_print.set(False)
            return
        
        def check_card():
            if self.auto_print.get():  # 只在自动模式开启时读卡
                self.read_id_card(silent=True)  # 静默读卡
                self.auto_read_timer = self.root.after(1000, check_card)  # 每秒检查一次
        
        check_card()

    def stop_auto_read(self):
        """停止自动读卡"""
        if self.auto_read_timer:
            self.root.after_cancel(self.auto_read_timer)
            self.auto_read_timer = None

    def read_id_card(self, silent=False):
        """读取身份证信息"""
        if not self.selected_package:
            if not silent:
                messagebox.showinfo("提示", "请先选择一个体检套餐")
            return

        if not silent:
            self.status_var.set("正在读取身份证...")
            self.root.update()
        
        # 读取身份证
        info = self.id_reader.read_card()
        
        if not info:
            if not silent:
                messagebox.showerror("错误", "读取身份证失败，请确保身份证正确放置或手动输入信息")
                self.status_var.set("读取身份证失败")
            return
        
        # 检查是否与上一次读取的信息相同
        current_id = info.get("身份证号", "")
        last_id = self.patient_info.get("身份证号", "")
        if current_id and current_id == last_id:
            return  # 如果是同一张身份证，不重复处理
        
        # 更新输入框的值
        if "姓名" in info:
            self.patient_entries["姓名"].delete(0, tk.END)
            self.patient_entries["姓名"].insert(0, info["姓名"])
        
        if "性别" in info:
            self.patient_entries["性别"].set(info["性别"])
        
        if "年龄" in info:
            self.patient_entries["年龄"].delete(0, tk.END)
            self.patient_entries["年龄"].insert(0, info["年龄"])
        
        if "身份证号" in info:
            self.patient_entries["身份证号"].delete(0, tk.END)
            self.patient_entries["身份证号"].insert(0, info["身份证号"])
        
        # 保持单位字段不变
        
        # 保存患者信息
        self.save_patient_info()
        
        # 如果开启了自动打印，则自动打印体检单
        if self.auto_print.get():
            self.root.after(500, self.print_report)  # 延迟500毫秒后打印，确保信息已保存
        
        if not silent:
            self.status_var.set(f"已读取身份证信息: {info.get('姓名', '')}")
    
    def preview_report(self):
        """预览体检报告"""
        if not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个体检套餐")
            return
        
        if not self.patient_info:
            # 尝试使用测试数据
            use_test = messagebox.askyesno("提示", "未读取到身份证信息，是否使用测试数据?")
            if use_test:
                self.patient_info = {
                    "姓名": "杨小强",
                    "性别": "男",
                    "年龄": "46岁",
                    "身份证号": "510224197902096835"
                }
                self.update_patient_info_display()
            else:
                return
        
        # 生成报告
        temp_report_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 
                                        f"temp_{int(time.time())}.docx")
        
        report_path = self.printer.generate_report(self.patient_info, self.selected_package, temp_report_path)
        
        if not report_path:
            messagebox.showerror("错误", "生成报告失败")
            return
        
        # 预览报告
        if not self.printer.print_preview(report_path):
            messagebox.showerror("错误", "无法预览报告")
    
    def save_report(self):
        """保存体检报告"""
        if not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个体检套餐")
            return
        
        if not self.patient_info:
            # 尝试使用测试数据
            use_test = messagebox.askyesno("提示", "未读取到身份证信息，是否使用测试数据?")
            if use_test:
                self.patient_info = {
                    "姓名": "杨小强",
                    "性别": "男",
                    "年龄": "46岁",
                    "身份证号": "510224197902096835"
                }
                self.update_patient_info_display()
            else:
                return
        
        # 选择保存位置
        file_name = f"{self.patient_info.get('姓名', '未知')}_体检报告.docx"
        save_path = filedialog.asksaveasfilename(
            defaultextension=".docx",
            filetypes=[("Word文档", "*.docx")],
            initialfile=file_name,
            title="保存体检报告"
        )
        
        if not save_path:
            return
        
        # 生成报告
        report_path = self.printer.generate_report(self.patient_info, self.selected_package, save_path)
        
        if not report_path:
            messagebox.showerror("错误", "保存报告失败")
            return
        
        messagebox.showinfo("成功", f"体检报告已保存至:\n{report_path}")
        self.status_var.set(f"体检报告已保存")
    
    def print_report(self):
        """打印体检报告"""
        if not self.selected_package:
            messagebox.showinfo("提示", "请先选择一个体检套餐")
            return
        
        if not self.patient_info:
            # 尝试使用测试数据
            use_test = messagebox.askyesno("提示", "未读取到身份证信息，是否使用测试数据?")
            if use_test:
                self.patient_info = {
                    "姓名": "杨小强",
                    "性别": "男",
                    "年龄": "46岁",
                    "身份证号": "510224197902096835"
                }
                self.update_patient_info_display()
            else:
                return
        
        try:
            # 生成临时报告文件
            temp_report_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 
                                          f"temp_{int(time.time())}.docx")
            
            report_path = self.printer.generate_report(self.patient_info, self.selected_package, temp_report_path)
            
            if not report_path:
                messagebox.showerror("错误", "生成报告失败")
                return
            
            # 直接使用默认打印机打印
            success = self.printer.print_report(report_path, self.printer.get_default_printer())
            
            # 等待一段时间确保打印已经开始
            self.root.after(2000)  # 等待2秒
            
            if success:
                self.status_var.set(f"体检报告已打印完成: {self.patient_info.get('姓名', '')}")
            else:
                messagebox.showerror("错误", "打印报告失败")
                
        finally:
            # 确保延迟后再删除临时文件
            try:
                self.root.after(3000, lambda: os.remove(temp_report_path))  # 3秒后删除文件
            except:
                pass
    
    def save_patient_info(self):
        """保存手动输入的患者信息"""
        info = {}
        for key, entry in self.patient_entries.items():
            if isinstance(entry, ttk.Combobox):  # 性别下拉框
                value = entry.get()
            else:
                value = entry.get().strip()
            
            if not value and key not in ["年龄", "单位"]:  # 年龄和单位可以为空
                messagebox.showwarning("提示", f"请输入{key}")
                return
            
            info[key] = value
        
        # 更新患者信息
        self.patient_info = info
        self.status_var.set(f"已保存患者信息: {info.get('姓名', '')}")
    
    def clear_patient_info(self):
        """清除患者信息"""
        for entry in self.patient_entries.values():
            if isinstance(entry, ttk.Combobox):
                entry.set("")
            else:
                entry.delete(0, tk.END)
        
        self.patient_info = {}
        self.status_var.set("已清除患者信息")


def main():
    root = tk.Tk()
    app = HealthCheckApp(root)
    root.mainloop()


if __name__ == "__main__":
    main() 